//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include "namedevent.h"
#include "cthread.h"
#include "pseudo.h"
#include "pcentral.h"
#include "helper.h"
#include <aura.h>

CNamedEvent::~CNamedEvent()
{
    if (NULL != m_pName) {
        WStringBuf::Free(m_pName);
        m_pName = NULL;
    }
}

ECode CNamedEvent::Initialize(
    /* [in] */ WString name)
{
    Int32 length = name.GetLength(AURA_MAX_PATH) + 1;
    assert(!name.IsNullOrEmpty());

    m_pName = WStringBuf::Alloc(length);
    if (NULL == m_pName) {
        return E_OUT_OF_MEMORY;
    }
    m_pName->Copy(name);

    return NOERROR;
}

PInterface CNamedEvent::Probe(
    /* [in]  */ REIID riid)
{
    if (riid == EIID_IInterface) {
        return (PInterface)(IEvent *)this;
    }
    else if (riid == EIID_IEvent) {
        return (IEvent *)this;
    }
    else if (riid == EIID_CLASS_INFO) {
        return (PInterface)&ECLSID_CEvent;
    }
    else if (riid == EIID_INTERFACE_INFO) {
        return (PInterface)&EIID_IEvent;
    }

    return NULL;
}

UInt32 CNamedEvent::AddRef()
{
    Int32 nRef = m_cRef.Increment();
    return (UInt32)nRef;
}

UInt32 CNamedEvent::Release()
{
    Int32 nRef = m_cRef.Decrement();

    if (nRef == 0) {
        CNamedEventFactory factory(*m_pName);
        NamedObject::S_DestroyObject(&factory, m_oid);
        delete this;
    }
    return (UInt32)nRef;
}

ECode CNamedEvent::Aggregate(
    /* [in]  */ AggregateType type,
    /* [in]  */ PInterface pObj)
{
    return E_NOT_IMPLEMENTED;
}

ECode CNamedEvent::GetDomain(
    /* [out] */ PInterface * ppObj)
{
    return E_NOT_IMPLEMENTED;
}

ECode CNamedEvent::Wait(
    /* [out] */ WaitResult * pResult,
    /* [out] */ EventState * pState)
{
    if (NULL == pResult) {
        return E_INVALID_ARGUMENT;
    }

    return TryWait(INFINITE, pResult, pState);
}

ECode CNamedEvent::TryWait(
    /* [in]  */ Millisecond32 msTimeout,
    /* [out] */ WaitResult * pResult,
    /* [out] */ EventState * pState)
{
    ECode ec = NOERROR;

    if (NULL == pResult) {
        return E_INVALID_ARGUMENT;
    }

    THREAD_START_SLEEP_NAMED()
    {
        ec = CPseudoCentral::TrywaitNamedEvent(m_oid,
                                         msTimeout,
                                         pResult,
                                         pState);
    }
    THREAD_END_SLEEP_NAMED;

    return ec;
}

ECode CNamedEvent::Notify(
    /* [in ] */ EventState dwState)
{
    if (UNSIGNALED == dwState) {
        return E_INVALID_ARGUMENT;
    }

    return CPseudoCentral::NotifyNamedEvent(m_oid, dwState);
}

ECode CNamedEvent::Clear()
{
    return CPseudoCentral::ClearNamedEvent(m_oid);
}

ECode CNamedEventFactory::CreateNamedObject(
            /* [out] */ NamedObject ** ppNamedObj,
            /* [out] */ Boolean * pbAlreadyExisted)
{
    CNamedEvent * pEvent = NULL;
    ECode ec = NOERROR;
    oid_t oid = 0;

    assert(NULL != ppNamedObj);
    assert(NULL != pbAlreadyExisted);

    ec = CPseudoCentral::CreateNamedEvent(m_name,
                                          m_bManualReset,
                                          m_eventState,
                                          pbAlreadyExisted,
                                          &oid);
    if (FAILED(ec)) {
        goto ErrorExit;
    }

    pEvent = new CNamedEvent(oid);
    if (NULL == pEvent) {
        ec = E_OUT_OF_MEMORY;
        goto ErrorExit;
    }
    ec = pEvent->Initialize(m_name);
    if (FAILED(ec)) {
        goto ErrorExit;
    }

    pEvent->AddRef();
    *ppNamedObj = pEvent;

    return ec;

ErrorExit:
    if (NULL != pEvent) {
        delete pEvent;
    }
    if (oid > 0) {
        CPseudoCentral::ReleaseNamedObject(oid);
        oid = 0;
    }
    return ec;
}

ECode CNamedEventFactory::ResolveNamedObject(
            /* [in] */ oid_t oid,
            /* [out] */ NamedObject ** ppNamedObj)
{
    CNamedEvent * pEvent = NULL;
    ECode ec = NOERROR;

    assert(NULL != ppNamedObj);

    pEvent = new CNamedEvent(oid);
    if (NULL == pEvent) {
        ec = E_OUT_OF_MEMORY;
        goto ErrorExit;
    }
    ec = pEvent->Initialize(m_name);
    if (FAILED(ec)) {
        goto ErrorExit;
    }

    ec = CPseudoCentral::AddRefNamedObject(oid);
    if (FAILED(ec)) {
        goto ErrorExit;
    }

    pEvent->AddRef();
    *ppNamedObj = pEvent;

    return ec;

ErrorExit:
    if (NULL != pEvent) {
        delete pEvent;
    }
    return ec;
}

ECode CNamedEventFactory::DestroyNamedObject(
            /* [in]  */ oid_t oid)
{
    return CPseudoCentral::ReleaseNamedObject(oid);
}

